home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmcd-1.4 / libdi.d / os_linux.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-10  |  7.2 KB  |  339 lines

  1. /*
  2.  *   libdi - CD Audio Player Device Interface Library
  3.  *
  4.  *   Copyright (C) 1995  Ti Kan
  5.  *   E-mail: ti@amb.org
  6.  *
  7.  *   This program is free software; you can redistribute it and/or modify
  8.  *   it under the terms of the GNU General Public License as published by
  9.  *   the Free Software Foundation; either version 2 of the License, or
  10.  *   (at your option) any later version.
  11.  *
  12.  *   This program is distributed in the hope that it will be useful,
  13.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *   GNU General Public License for more details.
  16.  *
  17.  *   You should have received a copy of the GNU General Public License
  18.  *   along with this program; if not, write to the Free Software
  19.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  *
  21.  *   This software module contains code that interfaces the CD player
  22.  *   application to the Linux operating system.
  23.  */
  24. #ifndef LINT
  25. static char *_os_linux_c_ident_ = "@(#)os_linux.c    5.11 94/12/28";
  26. #endif
  27.  
  28. #include "common.d/appenv.h"
  29. #include "common.d/util.h"
  30. #include "libdi.d/libdi.h"
  31. #include "libdi.d/scsipt.h"
  32.  
  33. #if defined(linux) && defined(DI_SCSIPT) && !defined(DEMO_ONLY)
  34.  
  35. extern appdata_t    app_data;
  36. extern bool_t        scsipt_notrom_error;
  37. extern FILE        *errfp;
  38.  
  39. STATIC int        pthru_fd = -1;    /* Passthrough device file desc */
  40.  
  41.  
  42. /*
  43.  * pthru_send
  44.  *    Build SCSI CDB and send command to the device.
  45.  *
  46.  * Args:
  47.  *    opcode - SCSI command opcode
  48.  *    addr - The "address" portion of the SCSI CDB
  49.  *    buf - Pointer to data buffer
  50.  *    size - Number of bytes to transfer
  51.  *    rsvd - The "reserved" portion of the SCSI CDB
  52.  *    length - The "length" portion of the SCSI CDB
  53.  *    param - The "param" portion of the SCSI CDB
  54.  *    control - The "control" portion of the SCSI CDB
  55.  *    rw - Data transfer direction flag (READ_OP or WRITE_OP)
  56.  *    prnerr - Whether an error message should be displayed
  57.  *         when a command fails
  58.  *
  59.  * Return:
  60.  *    TRUE - command completed successfully
  61.  *    FALSE - command failed
  62.  */
  63. bool_t
  64. pthru_send(
  65.     byte_t        opcode,
  66.     word32_t    addr,
  67.     byte_t        *buf,
  68.     word32_t    size,
  69.     byte_t        rsvd,
  70.     word32_t    length,
  71.     byte_t        param,
  72.     byte_t        control,
  73.     byte_t        rw,
  74.     bool_t        prnerr
  75. )
  76. {
  77.     byte_t            *ptbuf;
  78.     byte_t            cdb[12];
  79.     int            ptbufsz,
  80.                 cdblen,
  81.                 ret;
  82.     req_sense_data_t    *rp;
  83.  
  84.     if (pthru_fd < 0 || scsipt_notrom_error)
  85.         return FALSE;
  86.  
  87.     /* Linux hack: use SCSI_IOCTL_TEST_UNIT_READY instead of
  88.      * SCSI_IOCTL_SEND_COMMAND for test unit ready commands.
  89.      */
  90.     if (opcode == OP_S_TEST) {
  91.         DBGPRN(errfp, "\nSending SCSI_IOCTL_TEST_UNIT_READY\n");
  92.  
  93.         ret = ioctl(pthru_fd, SCSI_IOCTL_TEST_UNIT_READY, NULL);
  94.         if (ret == 0)
  95.             return TRUE;
  96.  
  97.         if (app_data.scsierr_msg && prnerr) {
  98.             fprintf(errfp,
  99.                 "SCSI_IOCTL_TEST_UNIT_READY failed: ret=0x%x\n",
  100.                 ret
  101.             );
  102.         }
  103.         return FALSE;
  104.     }
  105.  
  106.     memset(cdb, 0, sizeof(cdb));
  107.  
  108.     /* set up SCSI CDB */
  109.     switch (opcode & 0xf0) {
  110.     case 0xa0:
  111.     case 0xe0:
  112.         /* 12-byte commands */
  113.         cdb[0] = opcode;
  114.         cdb[1] = param;
  115.         cdb[2] = (addr >> 24) & 0xff;
  116.         cdb[3] = (addr >> 16) & 0xff;
  117.         cdb[4] = (addr >> 8) & 0xff;
  118.         cdb[5] = (addr & 0xff);
  119.         cdb[6] = (length >> 24) & 0xff;
  120.         cdb[7] = (length >> 16) & 0xff;
  121.         cdb[8] = (length >> 8) & 0xff;
  122.         cdb[9] = length & 0xff;
  123.         cdb[10] = rsvd;
  124.         cdb[11] = control;
  125.  
  126.         cdblen = 12;
  127.         break;
  128.  
  129.     case 0xc0:
  130.     case 0xd0:
  131.     case 0x20:
  132.     case 0x30:
  133.     case 0x40:
  134.         /* 10-byte commands */
  135.         cdb[0] = opcode;
  136.         cdb[1] = param;
  137.         cdb[2] = (addr >> 24) & 0xff;
  138.         cdb[3] = (addr >> 16) & 0xff;
  139.         cdb[4] = (addr >> 8) & 0xff;
  140.         cdb[5] = addr & 0xff;
  141.         cdb[6] = rsvd;
  142.         cdb[7] = (length >> 8) & 0xff;
  143.         cdb[8] = length & 0xff;
  144.         cdb[9] = control;
  145.  
  146.         cdblen = 10;
  147.         break;
  148.  
  149.     case 0x00:
  150.     case 0x10:
  151.         /* 6-byte commands */
  152.         cdb[0] = opcode;
  153.         cdb[1] = param;
  154.         cdb[2] = (addr >> 8) & 0xff;
  155.         cdb[3] = addr & 0xff;
  156.         cdb[4] = length & 0xff;
  157.         cdb[5] = control;
  158.  
  159.         cdblen = 6;
  160.         break;
  161.  
  162.     default:
  163.         if (app_data.scsierr_msg && prnerr)
  164.             fprintf(errfp, "0x%02x: Unknown SCSI opcode\n",
  165.                 opcode);
  166.         return FALSE;
  167.     }
  168.  
  169.     DBGDUMP("SCSI CDB bytes", cdb, cdblen);
  170.  
  171.  
  172.     /* Set up SCSI pass-through command/data buffer */
  173.     ptbufsz = (sizeof(int) << 1) + cdblen;
  174.     if (buf != NULL && size > 0)
  175.         ptbufsz += size;
  176.  
  177.     if ((ptbuf = (byte_t *) malloc(ptbufsz)) == NULL) {
  178.         cd_fatal_popup(app_data.str_fatal, app_data.str_nomemory);
  179.         return FALSE;
  180.     }
  181.  
  182.     memset(ptbuf, 0, ptbufsz);
  183.     memcpy(ptbuf + (sizeof(int) << 1), cdb, cdblen);
  184.  
  185.     if (buf != NULL && size > 0) {
  186.         if (rw == WRITE_OP) {
  187.             *((int *) ptbuf) = size;
  188.             memcpy(ptbuf + (sizeof(int) << 1) + cdblen, buf, size);
  189.         }
  190.         else
  191.             *(((int *) ptbuf) + 1) = size;
  192.     }
  193.  
  194.     /* Send the command down via the "pass-through" interface */
  195.     if ((ret = ioctl(pthru_fd, SCSI_IOCTL_SEND_COMMAND, ptbuf)) != 0) {
  196.         if (app_data.scsierr_msg && prnerr) {
  197.             fprintf(errfp, "CD audio: %s %s:\n",
  198.                 "SCSI command error on", app_data.device);
  199.             fprintf(errfp,
  200.                 "%s=0x%x %s=0x%x %s=0x%x %s=0x%x %s=0x%x\n",
  201.                 "Opcode", opcode,
  202.                 "Status", status_byte(ret),
  203.                 "Msg", msg_byte(ret),
  204.                 "Host", host_byte(ret),
  205.                 "Driver", driver_byte(ret));
  206.  
  207.             rp = (req_sense_data_t *)(void *)
  208.                 (ptbuf + (sizeof(int) << 1));
  209.  
  210.             if (rp->valid) {
  211.                 fprintf(errfp,
  212.                     "Key=0x%x Code=0x%x Qual=0x%x\n",
  213.                     rp->key, rp->code, rp->qual);
  214.             }
  215.         }
  216.  
  217.         free(ptbuf);
  218.         return FALSE;
  219.     }
  220.  
  221.     if (buf != NULL && rw == READ_OP && size > 0)
  222.         memcpy(buf, ptbuf + (sizeof(int) << 1), size);
  223.  
  224.     free(ptbuf);
  225.     return TRUE;
  226. }
  227.  
  228.  
  229. /*
  230.  * pthru_open
  231.  *    Open SCSI pass-through device
  232.  *
  233.  * Args:
  234.  *    path - device path name string
  235.  *
  236.  * Return:
  237.  *    TRUE - open successful
  238.  *    FALSE - open failed
  239.  */
  240. bool_t
  241. pthru_open(char *path)
  242. {
  243.     struct stat    stbuf;
  244.     char        errstr[ERR_BUF_SZ];
  245.     int        i,
  246.             ret;
  247.  
  248.     /* Force close on eject.  This is because Linux's
  249.      * SCSI_IOCTL_SEND_COMMAND ioctl does not work well
  250.      * when there is no CD loaded...
  251.      */
  252.     app_data.eject_close = TRUE;
  253.  
  254.     /* Check for validity of device node */
  255.     if (stat(path, &stbuf) < 0) {
  256.         sprintf(errstr, app_data.str_staterr, path);
  257.         cd_fatal_popup(app_data.str_fatal, errstr);
  258.         return FALSE;
  259.     }
  260.  
  261.     /* Linux CD-ROM device is a block special file! */
  262.     if (!S_ISBLK(stbuf.st_mode)) {
  263.         sprintf(errstr, app_data.str_noderr, path);
  264.         cd_fatal_popup(app_data.str_fatal, errstr);
  265.         return FALSE;
  266.     }
  267.  
  268.     if ((pthru_fd = open(path, O_RDONLY | O_EXCL)) < 0) {
  269.         DBGPRN(errfp, "Cannot open %s: errno=%d\n", path, errno);
  270.         return FALSE;
  271.     }
  272.  
  273.     /* Linux hack:  The CD-ROM driver allows the open to succeed
  274.      * even if there is no CD loaded.  We test for the existence of
  275.      * a disc with SCSI_IOCTL_TEST_UNIT_READY.
  276.      */
  277.     for (i = 0; i < 3; i++) {
  278.         DBGPRN(errfp, "\nSending SCSI_IOCTL_TEST_UNIT_READY\n");
  279.  
  280.         ret = ioctl(pthru_fd, SCSI_IOCTL_TEST_UNIT_READY, NULL);
  281.         if (ret == 0)
  282.             break;
  283.  
  284.         if (app_data.scsierr_msg && app_data.debug) {
  285.             fprintf(errfp,
  286.                 "SCSI_IOCTL_TEST_UNIT_READY failed: ret=0x%x\n",
  287.                 ret
  288.             );
  289.         }
  290.     }
  291.     if (ret != 0) {
  292.         /* No CD loaded */
  293.         pthru_close();
  294.         return FALSE;
  295.     }
  296.  
  297.     return TRUE;
  298. }
  299.  
  300.  
  301. /*
  302.  * pthru_close
  303.  *    Close SCSI pass-through device
  304.  *
  305.  * Args:
  306.  *    Nothing.
  307.  *
  308.  * Return:
  309.  *    Nothing.
  310.  */
  311. void
  312. pthru_close(void)
  313. {
  314.     if (pthru_fd >= 0) {
  315.         close(pthru_fd);
  316.         pthru_fd = -1;
  317.     }
  318. }
  319.  
  320.  
  321. /*
  322.  * pthru_vers
  323.  *    Return OS Interface Module version string
  324.  *
  325.  * Args:
  326.  *    Nothing.
  327.  *
  328.  * Return:
  329.  *    Module version text string.
  330.  */
  331. char *
  332. pthru_vers(void)
  333. {
  334.     return ("OS Interface module (for Linux)\n");
  335. }
  336.  
  337. #endif    /* linux DI_SCSIPT DEMO_ONLY */
  338.  
  339.